package uk.ac.ebi.bioinvindex.services;

/** The class is taken from Rich faces examples.
 *
 * User: Nataliya Sklyar (nsklyar@ebi.ac.uk)
 * Date: Oct 26, 2007
 */


import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.model.Range;
import org.ajax4jsf.model.SequenceRange;
import org.ajax4jsf.model.SerializableDataModel;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;

import javax.faces.context.FacesContext;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Name("studyBeanModel")
public class StudyBeanModel extends SerializableDataModel {

	@In
	private IStudyBeanProvider studyBeanProvider;

	private Long currentPk;
	private Map<Long, StudyBean> wrappedData = new HashMap<Long, StudyBean>();
	private List<Long> wrappedKeys = null;
	private boolean detached = false;

	private static final long serialVersionUID = -1956179896877538628L;


	/**
	 * This method never called from framework.
	 * <p/>
	 * (non-Javadoc)
	 *
	 * @see org.ajax4jsf.model.ExtendedDataModel#getRowKey()
	 */

	@Override
	public Object getRowKey() {
		return currentPk;
	}

	/**
	 * This method normally called by Visitor before request Data Row.
	 */

	@Override
	public void setRowKey(Object key) {
		this.currentPk = (Long) key;
	}

	/**
	 * This is main part of Visitor pattern. Method called by framework many times during request processing.
	 */

	@Override
	public void walk(FacesContext context, DataVisitor visitor, Range range, Object argument) throws IOException {
		int firstRow = ((SequenceRange) range).getFirstRow();
		int numberOfRows = ((SequenceRange) range).getRows();
//		if (detached) { // Is this serialized model
// Here we just ignore current Rage and use whatever data was saved in serialized model.
// Such approach uses much more getByPk() operations, instead of just one request by range.
// Concrete case may be different from that, so you can just load data from data provider by range.
// We are using wrappedKeys list only to preserve actual order of items
//			for (Long key : wrappedKeys) {
//				setRowKey(key);
//				visitor.process(context, key, argument);
//			}
//		} else { // if not serialized, than we request data from data provider
		wrappedKeys = new ArrayList<Long>();
		for (StudyBean studyBean : studyBeanProvider.getItemsByRange(firstRow, numberOfRows)) {
			wrappedKeys.add(studyBean.getStudy().getId());
			wrappedData.put(studyBean.getStudy().getId(), studyBean);
			visitor.process(context, studyBean.getStudy().getId(), argument);
		}

//		}

	}

	/**
	 * This method must return actual data rows count from the Data Provider. It is used by pagination control
	 * <p/>
	 * to determine total number of data items.
	 */

	private Integer rowCount; // better to buffer row count locally

	@Override
	public int getRowCount() {
		if (rowCount == null) {
			rowCount = new Integer(getStudyBeanProvider().getRowCount());
			return rowCount.intValue();
		} else {
			return rowCount.intValue();
		}
	}

	/**
	 * This is main way to obtain data row. It is intensively used by framework.
	 * <p/>
	 * We strongly recommend use of local cache in that method.
	 */
	@Override
	public Object getRowData() {
		if (currentPk == null) {
			return null;
		} else {
			StudyBean ret = wrappedData.get(currentPk);
			if (ret == null) {
				ret = getStudyBeanProvider().getStudyBeanById(currentPk);
				wrappedData.put(currentPk, ret);
				return ret;
			} else {

				return ret;

			}

		}
	}

	/**
	 * Unused rudiment from old JSF staff.
	 */
	@Override
	public int getRowIndex() {
		throw new UnsupportedOperationException();
	}


	/**
	 * Unused rudiment from old JSF staff.
	 */
	@Override
	public Object getWrappedData() {
		throw new UnsupportedOperationException();
	}


	/**
	 * Never called by framework.
	 */
	@Override
	public boolean isRowAvailable() {
		if (currentPk == null) {
			return false;
		} else {
			return getStudyBeanProvider().hasStudyBeanById(currentPk);
		}
	}


	/**
	 * Unused rudiment from old JSF staff.
	 */
	@Override
	public void setRowIndex(int rowIndex) {
		throw new UnsupportedOperationException();
	}


	/**
	 * Unused rudiment from old JSF staff.
	 */

	@Override
	public void setWrappedData(Object data) {
		throw new UnsupportedOperationException();
	}


	/**
	 * This method suppose to produce SerializableDataModel that will be serialized into View State and used on a post-back.
	 * <p/>
	 * In current implementation we just mark current model as serialized. In more complicated cases we may need to
	 * <p/>
	 * transform data to actually serialized form.
	 */
	public SerializableDataModel getSerializableModel(Range range) {
		if (wrappedKeys != null) {
			detached = true;

// Some activity to detach persistent data from wrappedData map may be taken here.
// In that specific case we are doing nothing.

			return this;
		} else {
			return null;
		}

	}

	/**
	 * This is helper method that is called by framework after model update. In must delegate actual database update to
	 * <p/>
	 * Data Provider.
	 */

	@Override
	public void update() {
		System.out.println("StudyBeanModel.update");
//		throw new UnsupportedOperationException();
	}


	public IStudyBeanProvider getStudyBeanProvider() {
		return studyBeanProvider;
	}


	public void setStudyBeanProvider(StudyBeanProvider studyBeanProvider) {
		this.studyBeanProvider = studyBeanProvider;
	}

}











